#include <iostream>
#include <sstream>
#include "View3DOrtho.h"
#include "config.h"

View3DOrtho* View3DOrtho::instance = 0;
/*
 * callBack permettant d'appeler la fonction setRefreshView de View3DOrtho
 */
void canRefreshViewCallBack(int val) {
	View3DOrtho::getInstance()->setRefreshView(true);
}
View3DOrtho::View3DOrtho() :
		View3D() {
	refreshView = true;
}

void View3DOrtho::viewPortMiddle() { //view contenant le jeu
	/*dans la viewport nous avons besoin des propriétés relatif à la 3D*/
	//la viewport1 prend 2.5/5 de la fênetre
	glViewport(0, (h_global * 1.5) / 5, w_global, (h_global * 2.5) / 5); // Taille et positionnement de la viewport
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();

	gererProjection();

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();

	gererLookAt();
	initLights();
}

void View3DOrtho::gererProjection() {
	/*
	 * initialiser du type de projection parralèle en lui fournissant
	 * notamment un coin gauche droite haut et bas correspondant
	 * à la taille du labyrinthe
	 */
	float zoomFactor;
	if (model->isModeFirstPerson()) {
		zoomFactor = 0.4; //zoom First Person
	} else {
		zoomFactor = model->getZoomFactor(); //1= zoom neutre, >1 plus petit, <1 plus grand
	}
	float left = -model->getLabyrinthe()->getMatrixWidth() / 1.96;
	float right = model->getLabyrinthe()->getMatrixWidth() / 2;
	float top = model->getLabyrinthe()->getMatrixHeight() / 2;
	float bottom = -model->getLabyrinthe()->getMatrixHeight() / 2;

	glOrtho(left * zoomFactor, right * zoomFactor, bottom * zoomFactor,
			top * zoomFactor, 0, 100);
}

void View3DOrtho::gererLookAt() {
	PacMan pacman = model->getPacMan();
	//position ortogonale pacman en X
	pacmanX = -(pacman.getCurrentPosX()
			- (model->getLabyrinthe()->getMatrixWidth() / 2.0));
	//position ortogonale pacman en Y
	pacmanY = pacman.getCurrentPosY()
			- (model->getLabyrinthe()->getMatrixHeight() / 2.0);
	if (!pacman.isIdle()) {
		applySmoothLookAt();
	}

	if (model->isModeFirstPerson()) {

		int ratioX = 0;
		int ratioY = 0;
		float distance = 1.5;
		if (pacman.getCurrentDirection() == RIGHTDIRECTION) {
			ratioX += -distance;
		} else if (pacman.getCurrentDirection() == LEFTDIRECTION
				|| pacman.getCurrentDirection() == NONEDIRECTION) {
			ratioX += +distance;
		} else if (pacman.getCurrentDirection() == UPDIRECTION) {
			ratioY += -distance;
		} else {
			ratioY += +distance;
		}
		gluLookAt(-pacmanX + ratioX, -pacmanY + ratioY, 2.0, -pacmanX - ratioX,
				-pacmanY - ratioY, 0.9, 0, 0, 1);

	} else {
		glRotated(model->getViewRotation(), 0, 0, 1);
		if (model->getZoomFactor() < 1.0) { //si il y a un zoom avant par rapport à la position neutral
			gluLookAt(-pacmanX, -pacmanY - 3, 5, -pacmanX, -pacmanY, 0, 0,
					1, 0);
		} else { //pas de zoom ou zoom arrière
			gluLookAt(0, -3, 5, 0, 1, 0, 0, 1, 0);
		}
	}
}
/*
 * définit si la caméra peut être déplacée ou non
 */
void View3DOrtho::setRefreshView(bool value) {
	refreshView = value;
}
/*
 * Pattern singleton
 */
View3DOrtho* View3DOrtho::getInstance() {
	if (View3DOrtho::instance == 0)
		instance = new View3DOrtho();
	return instance;
}

void View3DOrtho::initLights() {

	enableLight();
	glEnable(GL_LIGHT0); // on allume/active la lumière 0, on garde les valeurs par défaut
	glEnable(GL_LIGHT1); // on allume/active la lumière 1, initialisé plus haut
	glDisable(GL_LIGHT2);
	glDisable(GL_LIGHT3);


	
	/*On initialise le spot*/
	glLightfv(GL_LIGHT1, GL_AMBIENT, light1_ambient);
	glLightfv(GL_LIGHT1, GL_DIFFUSE, light1_diffuse);
	glLightfv(GL_LIGHT1, GL_POSITION, light1_position);
	glLightfv(GL_LIGHT1, GL_SPECULAR, light1_specular);
	//spot direction
	glLightfv(GL_LIGHT1, GL_SPOT_DIRECTION, light1_direction);
	glLightf(GL_LIGHT1, GL_SPOT_CUTOFF, 45.0);

	glLightf(GL_LIGHT1, GL_CONSTANT_ATTENUATION, 0.02);
	glLightf(GL_LIGHT1, GL_LINEAR_ATTENUATION, 0.02);
	glLightf(GL_LIGHT1, GL_QUADRATIC_ATTENUATION, 0.02);
	glLightf(GL_LIGHT1, GL_SPOT_EXPONENT, 0.0);

	/*Initialisation de lumière2 pour les gyrophares*/
	glLightfv(GL_LIGHT1, GL_AMBIENT, light1_ambient);
	glLightfv(GL_LIGHT1, GL_DIFFUSE, light1_diffuse);
	glLightfv(GL_LIGHT1, GL_POSITION, light1_position);
	glLightfv(GL_LIGHT1, GL_SPECULAR, light1_specular);

}
